<html>

<head>
    <title>俄罗斯方块</title>
    <style>
        html {
            background-color: rgb(22, 22, 22);
            color: rgb(14, 156, 76);
        }

        #score {
            color: red;
        }

        #rows {
            color: blue;
        }

        #left {

            display: inline-block;
            width: 230px;
            height: 600px;
        }

        #centre {
            position: relative;
            display: inline-block;
            width: 300px;
            height: 600px;
            vertical-align: top;
        }

        #right {
            display: inline-block;
            width: 230px;
            height: 600px;
            vertical-align: top;
        }

        #game {
            position: absolute;
            background-color: white;
            width: 300px;
            height: 600px;
        }

        #mask {
            position: absolute;
            background-color: rgb(134, 127, 134);
            width: 300px;
            height: 600px;
        }

        #start {
            position: absolute;
            left: 50%;
            top: 50%;
            width: 120px;
            height: 30px;
            margin-top: -15px;
            margin-left: -60px;
            background: rgb(124, 235, 161);
            color: rgb(2, 2, 14);
            font-weight: bold;
            padding: 13px 0;
            font-size: 20px;
            text-decoration: none;
            text-align: center;
            z-index: 999;

        }
    </style>
</head>

<body>
    <dir id="left">
        <p>分数(Score)：<span id="score">00000</span></p>
        <p>已消灭(Rows)：<span id="rows">0</span></p>
        <p>
            操作方法：<br />
            ↑：方块顺时针变形<br />
            ←：方块向左移动<br />
            →：方块向右移动<br />
            ↓：方块加速掉落
        </p>
    </dir>
    <dir id="centre">
        <canvas id="game"></canvas>

        <div id="mask">
            <a href="javascript:startGame();" id="start">开始游戏</a>
        </div>
    </dir>
    <dir id="right">
        <p id="next-msg">下一枚方块(Next)：</p>
        <canvas id="next"></canvas>
    </dir>
    <script>
        var I = {
            color: "red",
            maxWidth: 4,
            blocks: {
                0: [
                    [0, 0, 0, 0],
                    [1, 1, 1, 1],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                ],
                1: [
                    [0, 0, 1, 0],
                    [0, 0, 1, 0],
                    [0, 0, 1, 0],
                    [0, 0, 1, 0],
                ],
                2: [
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [1, 1, 1, 1],
                    [0, 0, 0, 0],
                ],
                3: [
                    [0, 1, 0, 0],
                    [0, 1, 0, 0],
                    [0, 1, 0, 0],
                    [0, 1, 0, 0],
                ],
            }
        };
        var L = {
            color: "red",
            maxWidth: 4,
            blocks: {
                0: [
                    [0, 0, 0, 0],
                    [0, 1, 0, 0],
                    [0, 1, 0, 0],
                    [0, 1, 1, 0],
                ],
                1: [
                    [0, 0, 0, 0],
                    [1, 1, 1, 0],
                    [1, 0, 0, 0],
                    [0, 0, 0, 0],
                ],
                2: [
                    [0, 1, 1, 0],
                    [0, 0, 1, 0],
                    [0, 0, 1, 0],
                    [0, 0, 0, 0],
                ],
                3: [
                    [0, 0, 0, 0],
                    [0, 0, 0, 1],
                    [0, 1, 1, 1],
                    [0, 0, 0, 0],
                ],
            }
        };
        var Z = {
            color: "red",
            maxWidth: 4,
            blocks: {
                0: [
                    [0, 0, 0, 0],
                    [0, 1, 0, 0],
                    [0, 1, 1, 0],
                    [0, 0, 1, 0],
                ],
                1: [
                    [0, 0, 0, 0],
                    [0, 1, 1, 0],
                    [1, 1, 0, 0],
                    [0, 0, 0, 0],
                ],
                2: [
                    [0, 1, 0, 0],
                    [0, 1, 1, 0],
                    [0, 0, 1, 0],
                    [0, 0, 0, 0],
                ],
                3: [
                    [0, 0, 0, 0],
                    [0, 0, 1, 1],
                    [0, 1, 1, 0],
                    [0, 0, 0, 0],
                ],
            }
        };
        //获取游戏画布
        var cvs = document.getElementById("game");
        //设置画布的逻辑大小等于它的物理大小
        cvs.Width = cvs.clientWidth;
        cvs.height = cvs.clientHeight;
        //获取游戏画布的画笔
        var brs = cvs.getContext('2d')
        //设置画笔不绘制边框
        brs.lineWidth = 0.0001;

        //在指定位置（x,y）
        //绘制指定类型piece、指定方向dir的方块
        function drawPiece(piece, dir, x, y) {
            //方块指定方向的十六宫格
            var blocks = piece.blocks[dir]
            //遍历十六宫格
            for (var row = 0; row < 4; row++) {
                for (var col = 0; col < 4; col++) {
                    //如果格子需要填充，则绘制格子
                    if (blocks[row][col] == 1) {

                        //设置画笔填充的颜色
                        brs.fillStyle = piece.color
                        //使用画笔绘制矩形
                        brs.fillRect(
                            (x + col) * 30,
                            (y + row) * 30,
                            30,
                            30
                        );
                    }
                }
            }
        }

        //开始游戏
        function startGame() {
            //获取按钮
            var b = document.getElementById("start");
            //获取蒙层
            var m = document.getElementById("mask");
            // 将其隐藏
            b.style.visibility = "hidden";
            m.style.visibility = "hidden";
            //drawPiece(I, 0, 1, 1);
            //drawPiece(I, 1, 5, 2);
            playing = true;
        }

        //记录方块的类型、方向和位置等数据
        var currentPiece = {
            type: L,//类型
            dir: 0,//方向
            x: 3,//X坐标
            y: 0,//Y坐标
        };
        var lastDropTime = 0;//最后一次下落的时间
        var setpSize = 800;//方块下落所需时长(毫秒)
        var playing = false; //游戏的开始/停止状态




        //游戏循环递归函数
        function gameloop() {
            //如果游戏中状态
            if (playing) {
                //根据玩家操作不断改变数据
                //处理玩家操作（会按改变相应的数据）
                hahdlePlayerAction();
                //根据游戏规则不断改变数据
                //处理自动下落（会改变相应的数据）
                handleAutoDrop();
                //抹除界面元素，再根据数据重新绘制
                redraw();
            }
            //画面每1/60秒刷新一次
            requestAnimationFrame(gameloop);
        }
        gameloop();

        function hahdlePlayerAction() {

        }
        //方块处理自动下落
        function handleAutoDrop() {
            //当前时间
            var now = new Date().getTime();
            //距离上一次方块自动下落的时长（毫秒）
            var duration = now - lastDropTime;
            //如果距离上次方块下落时长超过规定的步长，则增加方块的Y坐标
            if (duration > setpSize) {
                //增加当前方块Y坐标
                const tarX = currentPiece.x;
                const tarY = currentPiece.y + 1;
                const tarD = currentPiece.dir
                if (!obstacle(tarX, tarY, tarD)) {
                    currentPiece.y = tarY;
                } else {
                    //固化当前方块
                    fixCurPiece();
                    //重置当前方块
                    resetCurPiece();
                }
                //更新最后一次下落时间
                lastDropTime = now;
            }
        }

        //画布中的每个格子
        const grids = [
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ]
        //固定当前方块
        function fixCurPiece() {
            //当前方块的十六宫格
            const blks = currentPiece.type.blocks[currentPiece.dir];
            //遍历当前方块十六宫格
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    //十六宫格中的有效格子
                    if (blks[r][c] == 1) {
                        const row = currentPiece.y + r;
                        const col = currentPiece.x + c;
                        //标记画布
                        grids[row][col] = 1;
                    }
                }
            }
        }
        //根据最新数据重新绘制方块
        function redraw() {
            //清空游戏画布
            brs.clearRect(0, 0, 300, 600);
            //绘制方块
            drawPiece(
                currentPiece.type,
                currentPiece.dir,
                currentPiece.x,
                currentPiece.y
            )
            //绘制固定了的格子
            for (let r = 0; r < grids.length; r++) {
                for (let c = 0; c < grids[r].length; c++) {
                    //如果格子是填充状态
                    if (grids[r][c]) {
                        //设置画笔填充的颜色
                        brs.fillStyle = 'black';
                        //使用画笔绘制矩形
                        brs.fillRect(
                            c * 30,
                            r * 30,
                            30,
                            30
                        );
                    }
                }
            }
        }

        //重置当前方块
        function resetCurPiece() {
            currentPiece = {
                type: L,//类型
                dir: 0,//方向
                x: 3,//X坐标
                y: 0,//Y坐标
            };
        }
        //监听键盘按键事件
        document.addEventListener(
            'keydown',
            function (event) {
                if (playing == true) {
                    if (event.key == 'ArrowLeft') {
                        const tarX = currentPiece.x - 1;
                        const tarY = currentPiece.y;
                        const tarD = currentPiece.dir;
                        if (!obstacle(tarX, tarY, tarD)) {
                            currentPiece.x = tarX;
                        }
                    }
                    if (event.key == 'ArrowRight') {
                        const tarX = currentPiece.x + 1;
                        const tarY = currentPiece.y;
                        const tarD = currentPiece.dir;
                        if (!obstacle(tarX, tarY, tarD)) {
                            currentPiece.x = tarX;
                        }
                    }
                    if (event.key == 'ArrowDown') {
                        const tarX = currentPiece.x;
                        const tarY = currentPiece.y + 1;
                        const tarD = currentPiece.dir;
                        if (!obstacle(tarX, tarY, tarD)) {
                            currentPiece.y = tarY;
                        }
                    }
                    if (event.key == 'ArrowUp') {
                        const tarX = currentPiece.x;
                        const tarY = currentPiece.y;
                        let tarD = currentPiece.dir + 1;
                        if (tarD > 3) {
                            tarD = 0;
                        }
                        if (!obstacle(tarX, tarY, tarD)) {
                            currentPiece.dir = tarD;
                        }
                    }
                }
            }
        )

        //判断目标位置是否有障碍物
        function obstacle(tarX, tarY, tarD) {
            //当前方块的十六宫格
            const blks = currentPiece.type.blocks[tarD];
            //遍历当前方块十六宫格
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    //十六宫格中的有效格子
                    if (blks[r][c] == 1) {
                        if (
                            //目标位置穿越左侧边界
                            tarX + c < 0 ||
                            //目标位置穿越右侧边界
                            tarX + c >= cvs.width / 30 ||
                            //目标位置穿越下方边界
                            tarY + r >= cvs.height / 30 ||
                            //目标位置有固定的方块
                            grids[tarY + r][tarX + c]
                        ) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    </script>
</body>

</html>